package com.gulimall.ware.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gulimall.common.constrant.WareConstant;
import com.gulimall.common.enums.OrderStatusEnum;
import com.gulimall.common.to.WareSkuLockTo;
import com.gulimall.common.to.rabbit.WareLockTo;
import com.gulimall.common.utils.PageUtils;
import com.gulimall.common.utils.Query;
import com.gulimall.common.utils.R;
import com.gulimall.ware.dao.WareSkuDao;
import com.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.gulimall.ware.entity.WareOrderTaskEntity;
import com.gulimall.ware.entity.WareSkuEntity;
import com.gulimall.ware.exception.NoStockException;
import com.gulimall.ware.feign.FeignProductService;
import com.gulimall.ware.feign.OrderFeignService;
import com.gulimall.ware.service.WareOrderTaskDetailService;
import com.gulimall.ware.service.WareOrderTaskService;
import com.gulimall.ware.service.WareSkuService;
import com.gulimall.ware.vo.WareStockEntity;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {
    @Autowired
    private FeignProductService feignProductService;
    @Autowired
    private WareOrderTaskDetailService taskDetailService;
    @Autowired
    private WareOrderTaskService taskService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private OrderFeignService orderFeignService;

    @Override
    public void unLockStock(WareLockTo wareLockTo) {
        Long taskId = wareLockTo.getTaskId();
        WareOrderTaskEntity orderTaskEntity = taskService.getById(taskId);
        if (orderTaskEntity != null) {
            List<Long> skuIds =
                    wareLockTo.getLockItems().stream().map(WareLockTo.wareLockItem::getSkuId).collect(Collectors.toList());
            //远程查询订单的状态，状态为‘取消’ 就解锁商品
            R orderResult = orderFeignService.getOrderStatusBySkus(wareLockTo.getOrderSn());
            if (orderResult.getResult() == 0) {
                //解锁
                Integer orderStatus = (Integer) orderResult.get("orderStatus");
                if (orderStatus == null || orderStatus.equals(OrderStatusEnum.CANCLED.getCode())) {
                    unLockOrder(wareLockTo.getLockItems());
                }
            } else {
                log.error("远程查询订单状态错误 " + orderResult);
                //消息拒绝后，将消息重新放回队列中，让别人继续消费
                throw new RuntimeException("远程查询订单状态错误");
            }
        } else {
            //无需解锁
        }
    }

    @Override
    public void closeOrder(String orderSn) {
        WareOrderTaskEntity wareOrderTask = taskService.getOne(new QueryWrapper<WareOrderTaskEntity>().eq("order_sn",
                orderSn));
        Long taskId = wareOrderTask.getId();
        List<WareOrderTaskDetailEntity> taskDetailEntities =
                taskDetailService.list(new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", taskId));

        List<WareOrderTaskDetailEntity> lists = new ArrayList<>();
        for (WareOrderTaskDetailEntity taskDetailEntity : taskDetailEntities) {
            if (taskDetailEntity.getLockStatus() != WareConstant.WareLockStatus.LOCK.getCode()) {
                continue;
            }

            baseMapper.ubLockOrder(taskDetailEntity.getWareId(), taskDetailEntity.getSkuId(),
                    taskDetailEntity.getSkuNum());

            taskDetailEntity.setLockStatus(WareConstant.WareLockStatus.ASSIGNED.getCode());
            lists.add(taskDetailEntity);
        }
        taskDetailService.updateBatchById(lists);
    }

    private void unLockOrder(List<WareLockTo.wareLockItem> lockItems) {
        List<WareOrderTaskDetailEntity> lists = new ArrayList<>();

        for (WareLockTo.wareLockItem lockItem : lockItems) {
            WareOrderTaskDetailEntity wareOrderTaskDetailEntity = taskDetailService.getById(lockItem.getId());
            if (wareOrderTaskDetailEntity.getLockStatus() != WareConstant.WareLockStatus.LOCK.getCode()) {
                continue;
            }
            baseMapper.ubLockOrder(lockItem.getWareId(), lockItem.getSkuId(), lockItem.getSkuNum());

            wareOrderTaskDetailEntity.setId(lockItem.getId());
            wareOrderTaskDetailEntity.setLockStatus(WareConstant.WareLockStatus.ASSIGNED.getCode());
            lists.add(wareOrderTaskDetailEntity);
        }

        taskDetailService.updateBatchById(lists);
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>());

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageSkuWare(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> queryWrapper = new QueryWrapper<>();
        String skuId = (String) params.get("skuId");
        if (StringUtils.hasText(skuId) && !"0".equals(skuId)) {
            queryWrapper.eq("sku_id", skuId);
        }
        String wareId = (String) params.get("wareId");
        if (StringUtils.hasText(skuId) && !"0".equals(wareId)) {
            queryWrapper.eq("ware_id", wareId);
        }

        return new PageUtils(this.page(new Query<WareSkuEntity>().getPage(params), queryWrapper));
    }

    @Override
    public void saveProductWare(Long itemId, Long wareId, Integer skuNum) {
        List<WareSkuEntity> wareSkuEntities = list(new QueryWrapper<WareSkuEntity>().eq("sku_id", itemId).eq("ware_id"
                , wareId));
        if (wareSkuEntities == null || wareSkuEntities.size() == 0) {
            WareSkuEntity wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setSkuId(itemId);
            wareSkuEntity.setWareId(wareId);
            wareSkuEntity.setStock(skuNum);
            wareSkuEntity.setStockLocked(0);

            try {
                R r = feignProductService.productInfo(itemId);
                Map<String, Object> data = (Map<String, Object>) r.get("skuInfo");
                if (r.getResult() == 0) {
                    wareSkuEntity.setSkuName((String) data.get("skuName"));
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }

            save(wareSkuEntity);
        } else {
            baseMapper.saveWareStock(itemId, wareId, skuNum);
        }
    }

    @Override
    public Map<Long, Boolean> queryProductStock(List<Long> skuIds) {
        Map<Long, Boolean> result = new HashMap<>();
        var ref = new Object() {
            Long stock = 0L;
        };
        skuIds.forEach(item -> {
            List<WareSkuEntity> wareSkuEntities = list(new QueryWrapper<WareSkuEntity>().eq("sku_id", item));
            ref.stock = 0L;
            wareSkuEntities.forEach(wareSku -> {
                ref.stock += wareSku.getStock() - wareSku.getStockLocked();
            });
            result.put(item, ref.stock != 0);
        });

        return result;
    }

    /**
     * 锁定所有的库存信息
     *
     * @param wareSkuLockTo
     * @return
     */
    @Override
    @Transactional
    public boolean orderLockStock(WareSkuLockTo wareSkuLockTo) {
        //库存单
        WareOrderTaskEntity taskEntity = new WareOrderTaskEntity();
        taskEntity.setOrderSn(wareSkuLockTo.getOrderSn());
        taskEntity.setCreateTime(new Date());
        taskService.save(taskEntity);

        List<WareSkuLockTo.skuItem> skuItems = wareSkuLockTo.getSkuItems();

        //查询所有商品的 仓库信息
        List<WareStockEntity> skuWareInfos = skuItems.stream().map(item -> {
            WareStockEntity wareStockEntity = new WareStockEntity();
            wareStockEntity.setSkuId(item.getSkuId());
            wareStockEntity.setCount(item.getCount());
            List<Long> wareIds =
                    list(new QueryWrapper<WareSkuEntity>().eq("sku_id", item.getSkuId())).stream().map(WareSkuEntity::getWareId).collect(Collectors.toList());
            wareStockEntity.setWareId(wareIds);
            return wareStockEntity;
        }).collect(Collectors.toList());

        List<WareLockTo.wareLockItem> wareLockItems = new ArrayList<>();

        for (WareStockEntity skuWareInfo : skuWareInfos) {
            List<Long> wareIds = skuWareInfo.getWareId();
            if (wareIds == null || wareIds.size() < 1) {
                throw new NoStockException(skuWareInfo.getSkuId());
            }
            boolean hasStock = false;
            for (Long wareId : wareIds) {
                Integer num = baseMapper.judgingStock(wareId, skuWareInfo.getSkuId());
                if (num >= skuWareInfo.getCount()) {
                    hasStock = true;
                    baseMapper.updateSkuStock(wareId, skuWareInfo.getSkuId(), skuWareInfo.getCount());

                    WareOrderTaskDetailEntity detailEntity = new WareOrderTaskDetailEntity();
                    detailEntity.setSkuId(skuWareInfo.getSkuId());
                    detailEntity.setWareId(wareId);
                    detailEntity.setTaskId(taskEntity.getId());
                    detailEntity.setSkuNum(skuWareInfo.getCount());
                    detailEntity.setLockStatus(WareConstant.WareLockStatus.LOCK.getCode());
                    taskDetailService.save(detailEntity);

                    WareLockTo.wareLockItem wareLockItem = new WareLockTo.wareLockItem();
                    BeanUtils.copyProperties(detailEntity, wareLockItem);
                    wareLockItems.add(wareLockItem);

                    break;
                }
            }
            if (!hasStock) {
                throw new NoStockException();
            }
        }

        WareLockTo wareLockTo = new WareLockTo();
        wareLockTo.setLockItems(wareLockItems);
        wareLockTo.setOrderSn(wareSkuLockTo.getOrderSn());
        wareLockTo.setTaskId(taskEntity.getId());
        rabbitTemplate.convertAndSend(WareConstant.WARE_STOCK_EVENT_EXCHANGE, WareConstant.WARE_STOCK_LOCKED_KEY,
                wareLockTo);

        return true;
    }

}
